package d20chat;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;


/**
 * Handles starting a thread to listen for clients trying to connect to the server.
 * Also handles creating new threads for each client.
 * @author Scott
 */
public class ServerListener
{
    /**
     * Holds the current Server class.
     */
    private Server tempserv;
    /**
     * Holds the socket connection that we are listening to.
     */
    private ServerSocket listenSocket;
    /**
     * Stores the port that the server is functioning on.
     */
    private int port;
    /**
     * Holds the thread that the listener is going to run in.
     */
    private Thread ServerListenerThread;
    
    
/**
     * Class constructor for ServerListener.
     * @param serv Current instance of class Server.
     */
    public ServerListener(Server serv) 
    {
        tempserv = serv;
    } 
    

    
/**
     * Turns on the server thread and opens the server connection.
     * @param theport Port for the server to listen for new connections on.
     */
    public void StartServer(int theport)
    {
        //store the port the server will be running on
        port = theport;
        //try required for socket work
        //try to start up server and spin off listenerloop thread

        try  
        {
            //create the serversocket
            listenSocket = new ServerSocket ( port );

            //output message to know that the server started up
            //will want to call some other function in the future to let the user
            //know it was a success
            tempserv.ErrorMessageHandler ( "Server started! Listening on port " + port + "\n" );

            // Perform server start tasks (GUI stuff)
            tempserv.startServerTasks();

            //create a new mini-class and thread and get it ready to run ListenerLoop
            Thread listenthread = new Thread ( new Runnable() 
            {
                //the new thread will begin running here
                public void run ()
                {
                    //when started, the thread will enter into the listenerloop
                    ListenerLoop();
                }
            });
            //start up the new thread
            listenthread.start();


        }  
        catch (SocketException ex)
        {
            tempserv.stopServerTasks();
            //if the socket can not open, return an error
            //this will not handle listenerloop exceptions!
            tempserv.ErrorMessageHandler ( "Could not start server!\n" );

        }
        catch ( IOException e )  
        {
            tempserv.stopServerTasks();
            e.printStackTrace ();
            //display error message. Will want to code better error returning
            tempserv.ErrorMessageHandler ( "Unknown error starting server!\n" );
        }  // end catch
        
    }
    
    
    /**
     *Currently in order to send a message you pass the message
     *and the connection you are wanting to send on.
     *This will require the caller to know what connection we want to talk to
     *most likely this will be stored in the user class inside of the server class
     */
/**
     * Sends a message to a client connected to given socket.
     * This is used by Server to send messages onto clients. It must be passed the
     * message to be sent as well as the connection to send it to.
     * @param message Message to be sent to target client.
     * @param sendconnection Socket that message is to be sent to.
     */
    public void SendMessage(String message, Socket sendconnection)
    {
        //try required for socket streaming
        //try to send message out on the requested sendconnection
        try 
        {
            //attach the datastream to the connection and send it off
            OutputStream outStream = sendconnection.getOutputStream ();
            DataOutputStream outDataStream = new DataOutputStream ( outStream );
            outDataStream.writeUTF ( message );
        } 
        catch (IOException ex) 
        {
            //theoretically if the server tries to send a message to someone but they are connected
            //but have not been removed from the list yet, this one will throw.
            //not a big deal at all
            //if an error, don't send. Currently no feedback on a failed send
            //it just will fail silently
            //ex.printStackTrace();
        }
    }
    
    
    /**
     *ListenerLoop will be running in a seperate thread
     *It listens for connections on listenSocket. When found, it will start up a new
     *thread to handle the connection.
     *if the connection listenSocket is closed, this thread will close itself down
     *it will NOT close down the ServerThreads though!
     */
/**
     * 
     */
    private void ListenerLoop()
    {
        Socket connection; //holds the new client connection when one is initiated (before passing to a new thread
        
        //try required for socket connections
        try 
        {
            //loop forever, or until the socket listenSocket is closed
            while ( true )  
            {
                //listen for new connections. When found, assign them to connection
                connection = listenSocket.accept();
                //when connection established, build a new thread and pass it the connection
                //and ui
                ServerThread handleServer = new ServerThread ( connection, tempserv);
                //pass it this listener thread
                
                //begin execution in new thread
                handleServer.StartThread();
                tempserv.joinRoom(connection);
            }
        } 
        //if there is an error, the listenerloop will end. This will turn off the server
        //however it will NOT close the connections with the clients!
        catch (SocketException ex)
        {
            //assumably this is if the server has shut down.
            tempserv.ErrorMessageHandler ( "Server closed.\n" );
            tempserv.stopServerTasks();
        }
        catch (IOException ex) 
        {
            tempserv.Shutdown();
            //may be wise to have more error checking to see WHY it shut down, and perhaps
            //return info to the user
            //ex.printStackTrace();
            //ex.printStackTrace ();
            tempserv.ErrorMessageHandler ( "Server closed.\n" );
            tempserv.stopServerTasks();
        }
            
    }
    
    
    /**
     *This will close the listenersocket, however it will NOT close the client connections!
     */
/**
     * Shuts down the server.
     * Closes the socket used by the listener, which makes it so no one else can
     * connect.
     * Does not close any current connections. This only closes the listener.
     */
    public void StopServer()
    {
        try 
        {
            //closes connection
            //when connection closes, it will cause listenerloop to try
            //and read from a dead stream, which will throw a handled exception
            //and close down the thread
            listenSocket.close ();
            
            //output to chat informing of listenerSocket closed
        }  
        catch ( IOException except )  
        {
            //if closing fails for some reason or another, output to chat window
            //tempserv.ErrorMessageHandler ( "ServerListener: Unknown error closing listener socket!\n" );
            except.printStackTrace ();
        }
    }
    
    
}
